package com.leadingsoft.pwxk.service.impl;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.leadingsoft.common.exception.DataValidateException;
import com.leadingsoft.pwxk.dto.ApeDto;
import com.leadingsoft.pwxk.dto.ApesDto;
import com.leadingsoft.pwxk.dto.SearchDto;
import com.leadingsoft.pwxk.enums.MonthEnum;
import com.leadingsoft.pwxk.enums.PollutantEnum;
import com.leadingsoft.pwxk.enums.RiverBasinEnum;
import com.leadingsoft.pwxk.enums.StatisticalEnum;
import com.leadingsoft.pwxk.model.Category;
import com.leadingsoft.pwxk.model.QBaseInfo;
import com.leadingsoft.pwxk.model.QDrainInfoWaterApplyCountTwo;
import com.leadingsoft.pwxk.model.QLatestData;
import com.leadingsoft.pwxk.model.QLicenseInfo;
import com.leadingsoft.pwxk.model.QPwBaseInfo;
import com.leadingsoft.pwxk.model.RiverBasinRegionRelation;
import com.leadingsoft.pwxk.repository.CategoryRepository;
import com.leadingsoft.pwxk.repository.RiverBasinRegionRelationRepository;
import com.leadingsoft.pwxk.service.CategoryService;
import com.leadingsoft.pwxk.service.WPEStatisticalService;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.dsl.StringPath;
import com.querydsl.jpa.impl.JPAQuery;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class WPEStatisticalServiceImpl implements WPEStatisticalService {

	@Autowired
	private EntityManager em;

	QDrainInfoWaterApplyCountTwo drainInfoWaterApplyCountTwo = QDrainInfoWaterApplyCountTwo.drainInfoWaterApplyCountTwo;

	QLicenseInfo qLicenseInfo = QLicenseInfo.licenseInfo;

	QDrainInfoWaterApplyCountTwo qDrainInfoWaterApplyCountTwo = QDrainInfoWaterApplyCountTwo.drainInfoWaterApplyCountTwo;

	QPwBaseInfo qPwBaseInfo = QPwBaseInfo.pwBaseInfo;

	QBaseInfo qBaseInfo = QBaseInfo.baseInfo;

	QLatestData qLatestData = QLatestData.latestData;

	@Autowired
	CategoryRepository categoryRepository;

	@Autowired
	CategoryService categoryService;

	@Autowired
	RiverBasinRegionRelationRepository riverBasinRegionRelationRepository;

	@Override
	public ApesDto getStatistical(SearchDto s) {
		JPAQuery<Tuple> query = new JPAQuery<Tuple>(em);
		if (null == s.getStatisticalEnum()) {
			log.error("统计类型参数异常");
			throw new DataValidateException("统计类型参数异常");
		}
		if (s.getStatisticalEnum() != StatisticalEnum.YEAR && StringUtils.isBlank(s.getYear())) {
			log.error("非年度统计，年度参数不能为空");
			throw new DataValidateException("年度参数不能为空");
		}
		commonBuild(query);
		switch (s.getStatisticalEnum()) {
		case AREA:
			return getAreaStatistical(s, query);
		case INDUSTRY:
			return getIndustryStatistical(s);
		case RIVER_BASIN:
			return getRiverBasinStatistical(s, query);
		case YEAR:
			return getYearStatistical(s, query);
		default:
			log.error("统计类型参数异常");
			throw new DataValidateException("统计类型参数异常");
		}
	}

	private void commonBuild(JPAQuery<Tuple> query) {
		query.select(qDrainInfoWaterApplyCountTwo.sqoneyear, qDrainInfoWaterApplyCountTwo.sqtwoyear,
				qDrainInfoWaterApplyCountTwo.sqthreeyear, qDrainInfoWaterApplyCountTwo.sqfouryear,
				qDrainInfoWaterApplyCountTwo.sqfiveyear, qLicenseInfo.fztime.substring(0, 4), qBaseInfo.name_region,
				qBaseInfo.name_regiondetail, qDrainInfoWaterApplyCountTwo.waterwrwname, qBaseInfo.tradesname,
				qBaseInfo.wsystemname, qDrainInfoWaterApplyCountTwo.waterwrwcode, qBaseInfo.enterid,
				qLicenseInfo.fztime);
		query.from(qLatestData).leftJoin(qLicenseInfo).on(qLatestData.dataid.eq(qLicenseInfo.dataid));
		query.leftJoin(qDrainInfoWaterApplyCountTwo).on(qLicenseInfo.dataid.eq(qDrainInfoWaterApplyCountTwo.dataid))
				.leftJoin(qPwBaseInfo).on(qLicenseInfo.dataid.eq(qPwBaseInfo.dataid)).leftJoin(qBaseInfo)
				.on(qPwBaseInfo.enterid.eq(qBaseInfo.enterid));
		query.where(qDrainInfoWaterApplyCountTwo.waterwrwcode.in(PollutantEnum.CODCR.getCode(),
				PollutantEnum.AD.getCode()));
	}

	private ApesDto getAreaStatistical(SearchDto s, JPAQuery<Tuple> query) {
		if (StringUtils.isNotBlank(s.getCodeRegion())) {
			query.where(qBaseInfo.code_region.eq(s.getCodeRegion()));
			query.orderBy(qBaseInfo.code_regiondetail.asc());
			return getResult(query, Integer.parseInt(s.getYear()), qBaseInfo.name_regiondetail);
		} else {
			query.orderBy(qBaseInfo.code_region.asc());
			return getResult(query, Integer.parseInt(s.getYear()), qBaseInfo.name_region);
		}
	}

	private ApesDto getIndustryStatistical(SearchDto s) {
		List<Category> all = categoryRepository.findAll();
		List<Category> root = new ArrayList<Category>(64);
		if (StringUtils.isBlank(s.getHyid())) {
			all.forEach(t -> {
				if (StringUtils.isBlank(t.getParentCode())) {
					root.add(t);
				}
			});
		} else {
			Category category = categoryRepository.findByCode(s.getHyid());
			all.forEach(t -> {
				if (null != t.getParentCode() && t.getParentCode().equals(category.getCode())) {
					root.add(t);
				}
			});
		}
		List<ApeDto> list = new ArrayList<ApeDto>();
		root.forEach(t -> {
			JPAQuery<Tuple> query = new JPAQuery<Tuple>(em);
			commonBuild(query);
			List<String> childCodes = new ArrayList<String>(64);
			// 获取某个行业下的所有子类code
			categoryService.getChildCode(t, all, childCodes);
			query.where(qPwBaseInfo.hyid.in(childCodes));
			if (StringUtils.isNotBlank(s.getCodeRegion())) {
				query.where(qBaseInfo.code_region.eq(s.getCodeRegion()));
			}
			ApeDto apeDto = getYearResult(query, Integer.parseInt(s.getYear()), null);
			apeDto.setName(t.getName());
			list.add(apeDto);
		});
		ApesDto apesDto = new ApesDto();
		apesDto.setVal(list);
		return apesDto;
	}

	private ApesDto getRiverBasinStatistical(SearchDto s, JPAQuery<Tuple> query) {
		if (StringUtils.isNotBlank(s.getCodeRegion())) {
			query.where(qBaseInfo.code_region.eq(s.getCodeRegion()));
		}
		return getRiverBasinResult(query, Integer.parseInt(s.getYear()));
	}

	private ApesDto getYearStatistical(SearchDto s, JPAQuery<Tuple> query) {
		List<ApeDto> list = new ArrayList<ApeDto>();
		if (StringUtils.isBlank(s.getYear())) {
			Map<String, String> allFzTime = getAllFzTime();
			Integer startYear = Integer.parseInt(allFzTime.get("min"));
			Integer endYear = Integer.parseInt(allFzTime.get("max"));
			for (; startYear <= endYear; startYear++) {
				list.add(getYearResult(query, startYear, null));
			}
		} else {
			for (MonthEnum t : MonthEnum.values()) {
				list.add(getYearResult(query, Integer.parseInt(s.getYear()), t.getValue()));
			}
		}

		ApesDto apesDto = new ApesDto();
		apesDto.setVal(list);
		return apesDto;
	}

	private Map<String, String> getAllFzTime() {
		JPAQuery<Tuple> query = new JPAQuery<Tuple>(em);
		query.select(qLicenseInfo.fztime.substring(0, qLicenseInfo.fztime.indexOf("-")).max(),
				qLicenseInfo.fztime.substring(0, qLicenseInfo.fztime.indexOf("-")).min());
		query.from(qLicenseInfo);
		Tuple fetch = query.fetchFirst();
		Map<String, String> val = new HashMap<String, String>();
		val.put("max", fetch.get(0, String.class));
		val.put("min", fetch.get(1, String.class));
		return val;
	}

	private ApesDto getResult(JPAQuery<Tuple> query, Integer year, StringPath namePath) {
		List<Map<String, String>> data = new ArrayList<Map<String, String>>();
		List<Tuple> fetch = query.fetch();
		fetch.forEach(t -> {
			Map<String, String> tempMap = new HashMap<String, String>();
			tempMap.put("sqoneyear", t.get(qDrainInfoWaterApplyCountTwo.sqoneyear));
			tempMap.put("sqtwoyear", t.get(qDrainInfoWaterApplyCountTwo.sqtwoyear));
			tempMap.put("sqthreeyear", t.get(qDrainInfoWaterApplyCountTwo.sqthreeyear));
			tempMap.put("sqfouryear", t.get(qDrainInfoWaterApplyCountTwo.sqfouryear));
			tempMap.put("sqfiveyear", t.get(qDrainInfoWaterApplyCountTwo.sqfiveyear));
			tempMap.put("fztime", t.get(qLicenseInfo.fztime));
			tempMap.put("name", t.get(namePath));
			tempMap.put("waterwrwcode", t.get(qDrainInfoWaterApplyCountTwo.waterwrwcode));
			data.add(tempMap);
		});
		// 名称集合
		Set<String> nameSet = new LinkedHashSet<String>();
		// 数据 集合
		List<ApeDto> datas = new ArrayList<ApeDto>();
		data.forEach((val) -> {
			nameSet.add(val.get("name"));
		});
		DecimalFormat decimalFormat = new DecimalFormat();
		decimalFormat.applyPattern("0.000000");
		for (String t : nameSet) {
			double codcrTotal = 0.0;
			double adTotal = 0.0;
			for (Map<String, String> val : data) {
				if (t.equals(val.get("name")) && val.get("waterwrwcode").equals(PollutantEnum.CODCR.getCode())) {
					codcrTotal = dealSum(val, year, codcrTotal, null);
				}
				if (t.equals(val.get("name")) && val.get("waterwrwcode").equals(PollutantEnum.AD.getCode())) {
					adTotal = dealSum(val, year, adTotal, null);
				}
			}
			Map<String, Object> val = new HashMap<String, Object>();
			val.put(PollutantEnum.CODCR.getVal(), decimalFormat.format(codcrTotal));
			val.put(PollutantEnum.AD.getVal(), decimalFormat.format(adTotal));
			ApeDto apeDto = new ApeDto();
			apeDto.setName(t);
			apeDto.setValues(val);
			datas.add(apeDto);
		}
		ApesDto apesDto = new ApesDto();
		apesDto.setVal(datas);
		return apesDto;
	}

	private ApesDto getRiverBasinResult(JPAQuery<Tuple> query, Integer year) {
		List<Map<String, String>> data = new ArrayList<Map<String, String>>();
		List<Tuple> fetch = query.fetch();
		fetch.forEach(t -> {
			Map<String, String> tempMap = new HashMap<String, String>();
			tempMap.put("sqoneyear", t.get(qDrainInfoWaterApplyCountTwo.sqoneyear));
			tempMap.put("sqtwoyear", t.get(qDrainInfoWaterApplyCountTwo.sqtwoyear));
			tempMap.put("sqthreeyear", t.get(qDrainInfoWaterApplyCountTwo.sqthreeyear));
			tempMap.put("sqfouryear", t.get(qDrainInfoWaterApplyCountTwo.sqfouryear));
			tempMap.put("sqfiveyear", t.get(qDrainInfoWaterApplyCountTwo.sqfiveyear));
			tempMap.put("fztime", t.get(qLicenseInfo.fztime));
			tempMap.put("enterid", t.get(qPwBaseInfo.enterid));
			tempMap.put("waterwrwcode", t.get(qDrainInfoWaterApplyCountTwo.waterwrwcode));
			tempMap.put("nameRegion", t.get(qBaseInfo.name_region));
			tempMap.put("nameRegionDetail", t.get(qBaseInfo.name_regiondetail));
			data.add(tempMap);
		});
		// 名称集合
		Set<String> nameSet = new LinkedHashSet<String>();
		// 数据 集合
		List<ApeDto> datas = new ArrayList<ApeDto>();
		List<RiverBasinRegionRelation> rbs = riverBasinRegionRelationRepository.findAll();
		Map<String, List<RiverBasinRegionRelation>> allMap = new HashMap<String, List<RiverBasinRegionRelation>>();
		for (RiverBasinEnum e : RiverBasinEnum.values()) {
			nameSet.add(e.getVal());
			List<RiverBasinRegionRelation> temp = new ArrayList<RiverBasinRegionRelation>();
			rbs.forEach(t -> {
				if (t.getRiverBasinName().equals(e.getVal())) {
					temp.add(t);
				}
			});
			allMap.put(e.getVal(), temp);
		}
		DecimalFormat decimalFormat = new DecimalFormat();
		decimalFormat.applyPattern("0.000000");
		nameSet.forEach(t -> {
			double codcrTotal = 0.0;
			double adTotal = 0.0;
			for (Map<String, String> val : data) {
				for (RiverBasinRegionRelation r : allMap.get(t)) {
					if (val.get("waterwrwcode").equals(PollutantEnum.CODCR.getCode())
							&& r.getRegionName().indexOf(val.get("nameRegion")) != -1
							&& r.getRegionDetailName().indexOf(val.get("nameRegionDetail")) != -1) {
						codcrTotal = dealSum(val, year, codcrTotal, null);
					}
					if (val.get("waterwrwcode").equals(PollutantEnum.AD.getCode())
							&& r.getRegionName().indexOf(val.get("nameRegion")) != -1
							&& r.getRegionDetailName().indexOf(val.get("nameRegionDetail")) != -1) {
						adTotal = dealSum(val, year, adTotal, null);
					}
				}
			}
			Map<String, Object> val = new HashMap<String, Object>();
			val.put(PollutantEnum.CODCR.getVal(), decimalFormat.format(codcrTotal));
			val.put(PollutantEnum.AD.getVal(), decimalFormat.format(adTotal));
			ApeDto apeDto = new ApeDto();
			apeDto.setName(t);
			apeDto.setValues(val);
			datas.add(apeDto);
		});
		ApesDto apesDto = new ApesDto();
		apesDto.setVal(datas);
		return apesDto;
	}

	private ApeDto getYearResult(JPAQuery<Tuple> query, Integer year, Integer month) {
		List<Map<String, String>> data = new ArrayList<Map<String, String>>();
		List<Tuple> fetch = query.fetch();
		fetch.forEach(t -> {
			Map<String, String> tempMap = new HashMap<String, String>();
			tempMap.put("sqoneyear", t.get(qDrainInfoWaterApplyCountTwo.sqoneyear));
			tempMap.put("sqtwoyear", t.get(qDrainInfoWaterApplyCountTwo.sqtwoyear));
			tempMap.put("sqthreeyear", t.get(qDrainInfoWaterApplyCountTwo.sqthreeyear));
			tempMap.put("sqfouryear", t.get(qDrainInfoWaterApplyCountTwo.sqfouryear));
			tempMap.put("sqfiveyear", t.get(qDrainInfoWaterApplyCountTwo.sqfiveyear));
			tempMap.put("fztime", t.get(qLicenseInfo.fztime));
			tempMap.put("waterwrwcode", t.get(qDrainInfoWaterApplyCountTwo.waterwrwcode));
			data.add(tempMap);
		});
		double codcrTotal = 0.0;
		double adTotal = 0.0;
		for (Map<String, String> val : data) {
			if (val.get("waterwrwcode").equals(PollutantEnum.CODCR.getCode())) {
				codcrTotal = dealSum(val, year, codcrTotal, month);
			}
			if (val.get("waterwrwcode").equals(PollutantEnum.AD.getCode())) {
				adTotal = dealSum(val, year, adTotal, month);
			}
		}
		DecimalFormat decimalFormat = new DecimalFormat();
		decimalFormat.applyPattern("0.000000");
		Map<String, Object> val = new HashMap<String, Object>();
		val.put(PollutantEnum.CODCR.getVal(), decimalFormat.format(codcrTotal));
		val.put(PollutantEnum.AD.getVal(), decimalFormat.format(adTotal));
		ApeDto apeDto = new ApeDto();
		if (month != null) {
			apeDto.setName(MonthEnum.getDescByValue(month));
		} else {
			apeDto.setName(year.toString());
		}
		apeDto.setValues(val);
		return apeDto;
	}

	private double dealSum(Map<String, String> val, Integer year, double total, Integer month) {
		Integer fzYear = Integer.parseInt(val.get("fztime").substring(0, 4));
		Integer fzMonth = Integer.parseInt(val.get("fztime").substring(5, 7));
		Integer fzDay = Integer.parseInt(val.get("fztime").substring(8, 10));
		if (fzDay > 15) {
			if (fzMonth < 12) {
				fzMonth++;
			}
		}
		DecimalFormat decimalFormat = new DecimalFormat();
		decimalFormat.applyPattern("0.000000");
		double sqoneyear = 0.0;
		double sqtwoyear = 0.0;
		double sqthreeyear = 0.0;
		double sqfouryear = 0.0;
		double sqfiveyear = 0.0;
		Double temp = 0.0;
		if (null != val.get("sqoneyear") && !val.get("sqoneyear").equals("/") && !val.get("sqoneyear").equals("")) {
			sqoneyear = Double.valueOf(val.get("sqoneyear"));
		}
		if (null != val.get("sqtwoyear") && !val.get("sqtwoyear").equals("/") && !val.get("sqtwoyear").equals("")) {
			sqtwoyear = Double.valueOf(val.get("sqtwoyear"));
		}
		if (null != val.get("sqthreeyear") && !val.get("sqthreeyear").equals("/")
				&& !val.get("sqthreeyear").equals("")) {
			sqthreeyear = Double.valueOf(val.get("sqthreeyear"));
		}
		if (null != val.get("sqfouryear") && !val.get("sqfouryear").equals("/") && !val.get("sqfouryear").equals("")) {
			sqfouryear = Double.valueOf(val.get("sqfouryear"));
		}
		if (null != val.get("sqfiveyear") && !val.get("sqfiveyear").equals("/") && !val.get("sqfiveyear").equals("")) {
			sqfiveyear = Double.valueOf(val.get("sqfiveyear"));
		}
		if (null != month) {
			switch (year - fzYear) {
			case 0:
				if (month <= fzMonth) {
					temp = 0.0;
				} else {
					temp = sqoneyear / 12;
				}
				break;
			case 1:
				if (month <= fzMonth) {
					temp = sqoneyear / 12;
				} else {
					temp = sqtwoyear / 12;
				}
				break;
			case 2:
				if (month <= fzMonth) {
					temp = sqtwoyear / 12;
				} else {
					temp = sqthreeyear / 12;
				}
				break;
			case 3:
				if (month <= fzMonth) {
					temp = sqthreeyear / 12;
				} else {
					temp = sqfouryear / 12;
				}
				break;
			case 4:
				if (month <= fzMonth) {
					temp = sqfouryear / 12;
				} else {
					temp = sqfiveyear / 12;
				}
				break;
			default:
				break;
			}
		} else {
			switch (year - fzYear) {
			case 0:
				temp = sqoneyear * (12 - fzMonth) / 12;
				break;
			case 1:
				temp = sqtwoyear * (12 - fzMonth) / 12 + sqoneyear * fzMonth / 12;
				break;
			case 2:
				temp = sqthreeyear * (12 - fzMonth) / 12 + sqtwoyear * fzMonth / 12;
				break;
			case 3:
				temp = sqfouryear * (12 - fzMonth) / 12 + sqthreeyear * fzMonth / 12;
				break;
			case 4:
				temp = sqfiveyear * (12 - fzMonth) / 12 + sqfouryear * fzMonth / 12;
				break;
			default:
				break;
			}
		}
		total += Double.valueOf(decimalFormat.format(temp));
		return total;
	}

}
